{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"https://colab.research.google.com/github/stanfordnmbl/opencap-processing/blob/main/Examples/example_COM_analysis.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Effect of countermovement on jump height\n",
    "\n",
    "In this example, we will study the effect of countermovement on jump height when performing vertical jumps. We will use data measured with OpenCap of a participant performing vertical jumps with and without countermovement.\n",
    "\n",
    "We will go over several steps that include setting up the Colab environment, downloading and processing OpenCap data, and analyzing some results."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Install OpenSim using condacolab\n",
    "\n",
    "The first step is to install [condacolab](https://github.com/conda-incubator/condacolab) in your notebook. Once this is complete, you can use conda to install OpenSim into the environment. Note, this might take a few minutes to complete."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install -q condacolab\n",
    "import condacolab\n",
    "condacolab.install()\n",
    "!conda install -c opensim-org opensim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Import the opencap-processing source code\n",
    "\n",
    "This example is part of the opencap-processing Github repo. Let's clone this repo and install some Python packages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!git clone https://github.com/stanfordnmbl/opencap-processing.git\n",
    "%cd /content/opencap-processing\n",
    "!python3 -m pip install -r requirements.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the block above runs successfully, you should see that it installed several Python packages. You should get a message starting with:\n",
    "\n",
    "```\n",
    "Successfully installed ...\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Import packages\n",
    "\n",
    "Now that the correct Python packages have been installed and the source code has been cloned to this notebook, you can import packages specific to this script.\n",
    "\n",
    "Note, you will be prompted to login to OpenCap with your account. If you have not created an account yet, visit [app.opencap.ai](https://app.opencap.ai/register-nmbl). This will enable you to authenticate and analyze your own data in the future."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import sys\n",
    "sys.path.append(\"..\")\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import utilsKinematics\n",
    "from utils import download_kinematics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see a `Login successful` message."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Download data\n",
    "\n",
    "First, enter the session ID of the OpenCap data collection containing the jumping data. This will be used to download the data directly from OpenCap. We will share the session ID on the [confluence page of the workshop](https://simtk-confluence.stanford.edu:8443/display/OpenSim/ISB+Technical+Group+on+Computer+Simulation+%28TGCS%29+2023+OpenSim+Workshop) right after we collect data during the workshop. Note, you can also proceed with the example session ID below.\n",
    "\n",
    "Then, run the following block of code to download the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# Specify session id; see end of url in app.opencap.ai/session/<session_id>.\n",
    "session_id = \"3ef5cfad-cf8a-420b-af15-2d833a33cfb8\"\n",
    "\n",
    "# Specify trial names in a list; use None to process all trials in a session.\n",
    "specific_trial_names = None \n",
    "\n",
    "# Specify where to download the data.\n",
    "data_folder = os.path.join(\"./../Data\", session_id)\n",
    "\n",
    "# Download data.\n",
    "trial_names, modelName = download_kinematics(session_id, folder=data_folder, trialNames=specific_trial_names)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Process data\n",
    "\n",
    "Let's extract kinematic quantities using the OpenSim API. To do so, we use a class named `utilsKinematics.py`. Take a look at the `utilsKinematics.py` code in the github repo to see all the available functions.\n",
    "\n",
    "For this example, we will extract the center of mass values, speeds, and accelerations of the different trials."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get center of mass kinematics.\n",
    "kinematics, center_of_mass = {}, {}\n",
    "center_of_mass['values'], center_of_mass['speeds'], center_of_mass['accelerations'] = {}, {}, {}\n",
    "for trial_name in trial_names:\n",
    "    # Create object from class kinematics.\n",
    "    kinematics[trial_name] = utilsKinematics.kinematics(data_folder, trial_name, modelName=modelName, lowpass_cutoff_frequency_for_coordinate_values=10)\n",
    "    # Get center of mass values, speeds, and accelerations.\n",
    "    center_of_mass['values'][trial_name] = kinematics[trial_name].get_center_of_mass_values(lowpass_cutoff_frequency=10)\n",
    "    center_of_mass['speeds'][trial_name] = kinematics[trial_name].get_center_of_mass_speeds(lowpass_cutoff_frequency=10)\n",
    "    center_of_mass['accelerations'][trial_name] = kinematics[trial_name].get_center_of_mass_accelerations(lowpass_cutoff_frequency=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Analyze data (part 1)\n",
    "\n",
    "Let's now compare the center of mass values and speeds between our trials. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot center of mass vertical values and speeds.\n",
    "fig, axs = plt.subplots(2, 1, figsize=(6, 6), sharex=True)\n",
    "for trial_name in trial_names:\n",
    "    # Align signals based on peak velocity.\n",
    "    idx_peak_velocity = np.argmax(center_of_mass['speeds'][trial_name]['y'])\n",
    "    time = center_of_mass['speeds'][trial_name]['time']\n",
    "    x = time - time[idx_peak_velocity]\n",
    "    # Plot center of mass values.\n",
    "    y_values = center_of_mass['values'][trial_name]['y']\n",
    "    y = y_values-y_values[0]\n",
    "    axs[0].plot(x, y, label=trial_name, linewidth=3)\n",
    "    # Plot center of mass speeds.\n",
    "    y_speeds = center_of_mass['speeds'][trial_name]['y']\n",
    "    y = y_speeds-y_speeds[0]\n",
    "    axs[1].plot(x, y, label=trial_name, linewidth=3)\n",
    "    \n",
    "# Figure setttings.\n",
    "for ax in axs:\n",
    "    # Add labels.    \n",
    "    ax.legend(fontsize=14)\n",
    "    # Remove top and right borders.\n",
    "    ax.spines['top'].set_visible(False)\n",
    "    ax.spines['right'].set_visible(False)\n",
    "    # Change font size.\n",
    "    ax.tick_params(axis='both', which='major', labelsize=16)\n",
    "    # Change size labels.\n",
    "    ax.xaxis.label.set_size(16)\n",
    "    ax.yaxis.label.set_size(16)\n",
    "# Add labels.\n",
    "axs[0].set_ylabel('CoM position (m)')\n",
    "axs[1].set_ylabel('CoM velocity (m/s)')\n",
    "axs[1].set_xlabel('Time (s)')\n",
    "fig.align_ylabels(axs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Analyze data (part 2)\n",
    "\n",
    "Finally, let's compare the vertical forces that results from the center of mass accelerations. To approximate these forces we will do a simple F = ma calculation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot vertical forces from accelerations (F=ma).\n",
    "fig, ax = plt.subplots(1, 1, figsize=(6, 3))\n",
    "gravity = 9.81\n",
    "for trial_name in trial_names:\n",
    "    # Align signals based on peak velocity.\n",
    "    idx_peak_velocity = np.argmax(center_of_mass['speeds'][trial_name]['y'])\n",
    "    time = center_of_mass['speeds'][trial_name]['time']\n",
    "    x = time - time[idx_peak_velocity]\n",
    "    # Plot vertical ground reaction force.\n",
    "    y_accelerations = center_of_mass['accelerations'][trial_name]['y']\n",
    "    y = (y_accelerations + gravity) / gravity # vGRF expressed in bodyweights: vGRF = m(a+g)/mg\n",
    "    ax.plot(x, y, label=trial_name, linewidth=3)\n",
    "\n",
    "# Figure setttings.\n",
    "# Add labels. \n",
    "ax.set_ylabel('vGRF (bodyweight)')\n",
    "ax.set_xlabel('Time (s)')   \n",
    "ax.legend(fontsize=14)\n",
    "# Remove top and right borders.\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.spines['right'].set_visible(False)\n",
    "# Change font size.\n",
    "ax.tick_params(axis='both', which='major', labelsize=16)\n",
    "# Change size labels.\n",
    "ax.xaxis.label.set_size(16)\n",
    "ax.yaxis.label.set_size(16)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Version 1.0\n",
    "\n",
    "Creators: Antoine Falisse, Scott Uhlrich.\n",
    "Last Updated on July 21, 2023\n",
    "\n",
    "You can also find a non-Colab version of this script [here](https://github.com/stanfordnmbl/opencap-processing/blob/main/Examples/example_COM_analysis.py)\n",
    "\n",
    "This notebook is made available under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py37",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
